package com.passion.solr.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.passion.common.base.PageVO;
import com.passion.common.exception.MyException;
import com.passion.common.frm.PageFrm;
import com.passion.common.util.HttpRequestUtil;
import com.passion.common.util.ReflectionUtil;
import com.passion.search.annotation.SolrIndex;
import com.passion.solr.config.SolrConfig;
import com.passion.solr.enums.SolrEnums;
import com.passion.solr.frm.SchemaFieldOperateFrm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.solr.core.mapping.SolrDocument;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 类描述：solr工具类
 *
 * @author ZhuYin
 * @since 2024年12月03日
 */
@Slf4j
@Component
@ConditionalOnBean(SolrConfig.class)
@SuppressWarnings("unused")
public class SolrUtil implements ApplicationContextAware {

    private static SolrClient solrClient;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SolrUtil.solrClient = applicationContext.getBean(SolrClient.class);
    }

    private static final String SCHEMA_FIELD_OPERATE_URL = "${solrHost}/${coreName}/schema?wt=json";

    /** solr全量导入接口 */
    private static final String SOLR_FULL_IMPORT_URL = "${solrHost}/${coreName}/dataimport?command=full-import&verbose=false&clean=false&commit=true&core=${coreName}&name=dataimport&_=${timestamp}&indent=on&wt=json";
    /** solr增量导入接口 */
    private static final String SOLR_DELTA_IMPORT_URL = "${solrHost}/${coreName}/dataimport?command=delta-import&verbose=false&clean=false&commit=true&core=${coreName}&name=dataimport&_=${timestamp}&indent=on&wt=json";
    /** solr导入状态查询接口 */
    private static final String SOLR_IMPORT_STATUS_URL = "${solrHost}/archives/dataimport?_=${timestamp}&command=status&indent=on&wt=json";

    /** solr更新document接口 */
    private static final String SOLR_UPDATE_URL = "${solrHost}/${coreName}/update?_=${timestamp}&commitWithin=1000&overwrite=true&wt=json";
    /** solr清空core的xml串 */
    private static final String CLEAR_SOLR_REQUEST_XML = "<delete><query>*:*</query></delete>";
    private static final String COMMIT_SOLR_REQUEST_XML = "<commit/>";


    /**
     * 方法说明：向solr的schema配置汇中添加或删除字段
     *
     * @param frm 字段操作参数对象
     * @return Map 返回：{"result": true, "message": ""} 或 {"result": false, "message": "xxx"}
     * @author ZhuYin
     * @since 2024年09月23日
     */
    public static Map<String, Object> operateField(SchemaFieldOperateFrm frm) {
        Map<String, Object> retMap = Maps.newHashMap();
        Map<String, Object> params = Maps.newHashMap();
        if (SolrEnums.SchemaFieldOperateType.deleteField.getCode().equals(frm.getOperateType())) {
            Map<String, String> fieldMap = Maps.newHashMap();
            fieldMap.put("name", frm.getName());
            params.put(frm.getOperateType(), fieldMap);
        } else if (SolrEnums.SchemaFieldOperateType.addField.getCode().equals(frm.getOperateType())) {
            Map<String, Object> fieldMap = Maps.newHashMap();
            fieldMap.put("name", frm.getName());
            fieldMap.put("type", frm.getType());
            fieldMap.put("indexed", frm.getIndexed());
            fieldMap.put("stored", frm.getStored());
            fieldMap.put("multiValued", frm.getMultiValued());
            params.put(frm.getOperateType(), fieldMap);
        }
        String url = SCHEMA_FIELD_OPERATE_URL.replace("${solrHost}", SolrConfig.host);
        if (StringUtils.isNotBlank(frm.getCoreName())) {
            // 传了core名称就是用传过来的名称
            url = url.replace("${coreName}", frm.getCoreName());
        } else {
            url = url.replace("${coreName}", SolrConfig.defaultCore);
        }

        Map<String, String> headers = Maps.newHashMap();
        // solr如果开启了权限认证，发送http请求需要设置此值
        if (SolrConfig.auth) {
            // 此处的密码为 solr 加密后的密码
            headers.put("Authorization", "Basic " + SolrConfig.enPassword);
        }
        boolean result = false;
        String errorMsg = "";
        try {
            Map resultMap = HttpRequestUtil.sendPost(url, headers, params, Map.class);
            if (resultMap != null && !resultMap.isEmpty()) {
                log.info("请求solr接口[{}]返回[{}]", url, resultMap);
                if (resultMap.containsKey("responseHeader") && !resultMap.containsKey("error")) {
                    JSONObject header = (JSONObject) resultMap.get("responseHeader");
                    Integer status = (Integer) header.get("status");
                    if (Objects.equals(status, 0)) {
                        result = true;
                        log.info("配置字段操作参数：{}, Solr的schema新增/删除字段[{}]成功", JSON.toJSONString(frm), frm.getName());
                    } else {
                        JSONObject error = (JSONObject) resultMap.get("error");
                        JSONArray jsonArray = (JSONArray) error.get("details");
                        JSONObject obj = (JSONObject)jsonArray.get(0);
                        JSONArray errorMessages = (JSONArray)obj.get("errorMessages");
                        errorMsg = (String)errorMessages.get(0);
                        log.error("配置字段操作参数：{}, Solr的schema新增/删除字段[{}]异常：{}", JSON.toJSONString(frm), frm.getName(), errorMsg);
                    }
                } else {
                    if (resultMap.containsKey("error")) {
                        JSONObject jsonObject = (JSONObject) resultMap.get("error");
                        JSONArray jsonArray = (JSONArray) jsonObject.get("details");
                        JSONObject detailObject = (JSONObject) jsonArray.get(0);
                        errorMsg = ((JSONArray) detailObject.get("errorMessages")).get(0).toString();
                        log.error("配置字段操作参数：{}, Solr的schema新增/删除字段异常：{}", JSON.toJSONString(frm), errorMsg);
                    } else if (resultMap.get("status") != null && (Integer) resultMap.get("status") != 0) {
                        errorMsg = resultMap.get("message") != null ? resultMap.get("message").toString() : "";
                        log.error("配置字段操作参数：{}, Solr的schema新增/删除字段异常：{}", JSON.toJSONString(frm), resultMap.get("message"));
                    }
                }
            }
        } catch (Exception e) {
            errorMsg = e.getMessage();
            log.error("配置字段操作参数：{}, Solr的schema新增/删除字段异常：", JSON.toJSONString(frm), e);
        }
        retMap.put("result", result);
        retMap.put("message", errorMsg);
        return retMap;
    }

    /**
     * 全量导入-使用solr自带的功能
     * 调用全量导入功能，记得最好加锁
     * @param coreName   核心名字
     * @param entityName 实体名称：ArchivesProject ArchivesFolder ArchivesFile ArchivesDocument
     * @return int 错误代号 0.成功 1.请求solr接口不通 2.请求solr接口返回错误 3.全量创建索引正在进行中
     * @author ZhuYin
     * @since 2023/04/19
     */
    public static int fullImport(String coreName, String entityName) {
        String url = SOLR_FULL_IMPORT_URL;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(entityName)) {
            url += ("&entity=" + entityName);
        }

        url = url.replace("${solrHost}", SolrConfig.host);
        url = url.replace("${coreName}", coreName);
        url = url.replace("${timestamp}", System.currentTimeMillis() + "");

        Map<String, String> headers = Maps.newHashMap();
        // solr如果开启了权限认证，发送http请求需要设置此值
        if (SolrConfig.auth) {
            // 此处的密码为 solr 加密后的密码
            headers.put("Authorization", "Basic " + SolrConfig.enPassword);
        }
        boolean result = false;
        Map map;
        try {
            map = HttpRequestUtil.sendPost(url, headers, null, Map.class);
        } catch (Exception e) {
            log.error("core:{} entityName:{} 发送全量创建索引请求异常：", coreName, entityName, e);
            return 1;
        }
        if (map != null && !map.isEmpty()) {
            JSONObject header = (JSONObject) map.get("responseHeader");
            Integer status = (Integer) header.get("status");
            if (Objects.equals(status, 0)) {
                result = true;
            }
        }
        if (result) {
            log.info("core:{} entityName:{}  全量创建索引成功", coreName, entityName);
            return 0;
        } else {
            log.info("core:{} entityName:{} 全量创建索引失败", coreName, entityName);
            return 2;
        }
    }

    /**
     * 方法说明：增量同步，直接使用solr自身的能力实现
     * 调用增量创建索引功能，最好记得加锁
     * @param coreName   核心名字
     * @param entityName 实体名称: 可供选择的值为Solr的 data-config.xml 中配置在该 core 下的实体名称
     *                   ArchivesProject    对应表   t_archives_project
     *                   ArchivesFolder     对应表   t_archives_folder
     *                   ArchivesFile       对应表   t_archives_file
     *                   ArchivesDocument   对应表   t_archives_document
     * @author ZhuYin
     * @since 2023/04/20
     */
    public static void deltaImport(String coreName, String entityName) {

        if (StringUtils.isBlank(coreName)) {
            coreName = SolrConfig.defaultCore;
        }

        String url = SOLR_DELTA_IMPORT_URL;
        if (org.apache.commons.lang3.StringUtils.isNotBlank(entityName)) {
            url += ("&entity=" + entityName);
        }
        url = url.replace("${solrHost}", SolrConfig.host);
        url = url.replace("${coreName}", coreName);
        url = url.replace("${timestamp}", String.valueOf(System.currentTimeMillis()));

        Map<String, String> headers = Maps.newHashMap();
        // solr如果开启了权限认证，发送http请求需要设置此值
        if (SolrConfig.auth) {
            // 此处的密码为 solr 加密后的密码
            headers.put("Authorization", "Basic " + SolrConfig.enPassword);
        }

        boolean result = false;

        Map map = null;
        try {
            map = HttpRequestUtil.sendPost(url, headers, null, Map.class);
        } catch (Exception e) {
            log.info("core:{} entityName={} 发送增量创建索引请求失败:", coreName, entityName, e);
        }
        if (map != null && !map.isEmpty()) {
            JSONObject header = (JSONObject) map.get("responseHeader");
            Integer status = (Integer) header.get("status");
            if (Objects.equals(status, 0)) {
                // String type = getType(entityName);
                // solr自身能力的增量索引成功后，异步处理其他字段补充工作
                // String type = BaseServiceBeanContext.archivesIndexService.getType(entityName);
                // BaseServiceBeanContext.archivesIndexService.fillOtherFields(type);
                result = true;
            }
        }
        if (result) {
            log.info("core:{} entityName={} 增量创建索引成功", coreName, entityName);
        } else {
            log.info("core:{} entityName={} 增量创建索引失败", coreName, entityName);
        }
    }

    /**
     * 查询solr正在执行的请求的执行状态(如大数据量创建全量索引)
     * busy-还在执行中
     *
     * @return boolean
     * @author ZhuYin
     * @since 2023/04/20
     */
    public static boolean solrRequestStatus() {
        String url = SOLR_IMPORT_STATUS_URL;
        url = url.replace("${solrHost}", SolrConfig.host);
        url = url.replace("${timestamp}", System.currentTimeMillis() + "");

        Map<String, String> headers = Maps.newHashMap();
        // solr如果开启了权限认证，发送http请求需要设置此值
        if (SolrConfig.auth) {
            // 此处的密码为 solr 加密后的密码
            headers.put("Authorization", "Basic " + SolrConfig.enPassword);
        }

        Map map;
        try {
            map = HttpRequestUtil.sendPost(url, headers, null, Map.class);
            if (map != null && !map.isEmpty()) {
                JSONObject header = (JSONObject) map.get("responseHeader");
                Integer status = (Integer) header.get("status");
                // 如果返回结果 不是 busy，则说明创建完成了 (外层status状态：idle-未执行导入 busy-正在执行导入)
                if (Objects.equals(status, 0) && !"busy".equals(map.get("status"))) {
                    return true;
                }
            }
        } catch (Exception e) {
            log.error("查询solr全量创建索引状态异常：", e);
        }
        return false;
    }

    /**
     * 清空 Solr 的指定集合
     *
     * @param coreName 核心名字
     * @return boolean
     * @author ZhuYin
     * @since 2023/04/19
     */
    public static boolean clearSolrCore(String coreName) {
        return executeSolrXmlRequest(coreName, CLEAR_SOLR_REQUEST_XML);
    }

    /**
     * 方法说明：在指定core下执行commit
     *
     * @param coreName 指定的core名称
     * @return boolean
     * @author ZhuYin
     * @since 2024年09月23日
     */
    public static boolean executeSolrXmlCommitRequest(String coreName) {
        return executeSolrXmlRequest(coreName, COMMIT_SOLR_REQUEST_XML);
    }

    /**
     * 向solr执行xml请求
     *
     * @param coreName 核心名字
     * @param xml      xml
     * @return boolean
     * @author ZhuYin
     * @since 2023/04/19
     */
    public static boolean executeSolrXmlRequest(String coreName, String xml) {
        String updateUrl = SOLR_UPDATE_URL;
        if (StringUtils.isBlank(coreName)) {
            coreName = SolrConfig.defaultCore;
        }
        updateUrl = updateUrl.replace("${solrHost}", SolrConfig.host);
        updateUrl = updateUrl.replace("${coreName}", coreName);
        updateUrl = updateUrl.replace("${timestamp}", String.valueOf(System.currentTimeMillis()));

        Map<String, String> headers = Maps.newHashMap();
        // solr如果开启了权限认证，发送http请求需要设置此值
        if (SolrConfig.auth) {
            // 此处的密码为 solr 加密后的密码
            headers.put("Authorization", "Basic " + SolrConfig.enPassword);
        }

        try {
            String xmlResp = HttpRequestUtil.postXmlRequest(updateUrl, headers, xml);
            if (StringUtils.isNotBlank(xmlResp) && xmlResp.contains("\"status\":0")) {
                log.info("清除core:{}数据成功", coreName);
                return true;
            }
        } catch (Exception e) {
            log.info("清除core:{}数据失败：", coreName, e);
        }
        log.info("清除core:{}数据失败", coreName);
        return false;
    }

    public static String transferJavaType(Class<?> javaType) {
        if (javaType.equals(String.class)) {
            return "string";
        } else if (javaType.equals(Integer.class) || javaType.equals(int.class)) {
            return "pint";
        } else if (javaType.equals(Long.class) || javaType.equals(long.class)) {
            return "plong";
        } else if (javaType.equals(Float.class) || javaType.equals(float.class)) {
            return "pfloat";
        } else if (javaType.equals(Double.class) || javaType.equals(double.class) || javaType.equals(BigDecimal.class)) {
            return "pdouble";
        } else if (javaType.equals(Boolean.class) || javaType.equals(boolean.class)) {
            return "boolean";
        } else if (javaType.equals(java.util.Date.class)) {
            return "pdate";
        } else {
            throw new IllegalArgumentException("Unsupported Java type: " + javaType);
        }
    }


    /**
     * 将in查询的字符串集合拆分成多个Solr查询子句。
     *
     * @param list 字符串集合
     * @return 由OR连接的Solr查询子串
     */
    public static String dealSolrQueryStr(String fieldName, List<String> list) {
        if (list == null || list.isEmpty()) {
            return "";
        }

        // 使用流和Collectors.groupingBy对ID进行分组
        List<String> idChunks = Lists.newArrayList();
        int chunkSize = 100;
        for (int i = 0; i < list.size(); i += chunkSize) {
            int end = Math.min(i + chunkSize, list.size());
            List<String> chunk = list.subList(i, end);
            // 对每个ID使用引号包裹，防止特殊字符影响查询
            String chunkQuery = fieldName+ ":(" + chunk.stream()
                    // 使用引号包裹每个字符串(避免字符串携带特殊符号导致查询不到正确数据的问题)
                    .map(item -> "\"" + item + "\"")
                    .collect(Collectors.joining(" ")) + ")";
            idChunks.add(chunkQuery);
        }

        // 使用空格（在Solr中表示OR）连接所有的子查询
        return "(" + String.join(" OR ", idChunks) + ")";
    }


    /**
     * 方法说明：向solr中保存对象(创建单个索引)
     * 注意：使用该方法保存的对象，类上必须使用 @SolrDocument(collection = "xxx") 注解，表示要保存到哪个core中
     *      类中的字段必须使用 @SolrIndex(name = "demo_type", type = "string", indexed = true, stored = true, multiValued = false) 注解
     * @param o 实体对象
     * @return boolean
     * @author ZhuYin
     * @since 2025年01月03日
     */
    public static boolean saveDocument(Object o) throws Exception {
        Field[] declaredFields = o.getClass().getDeclaredFields();
        SolrDocument coreAnno = o.getClass().getAnnotation(SolrDocument.class);
        if (coreAnno == null) {
            log.warn("实体类：{} 未添加[@SolrDocument]注解，无法创建索引", o);
            return false;
        }
        String coreName = coreAnno.collection();
        SolrInputDocument solrDocument = new SolrInputDocument();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            if ("id".equals(field.getName())) {
                solrDocument.addField("id", field.get(o));
            }
            // 只对加了 @SolrIndex 注解的字段创建索引
            SolrIndex annotation = field.getAnnotation(SolrIndex.class);
            if (annotation != null) {
                // 对于加了 @SolrIndex 注解的字段，创建索引
                String solrFieldName = annotation.name();
                String type = annotation.type();
                Object fieldValue = ReflectionUtil.getFieldValue(o, field.getName());
                if (fieldValue != null) {
                    solrDocument.addField(solrFieldName, fieldValue);
                }
            }
        }
        // 添加文档到 Solr
        if (SolrConfig.logEnabled) {
            log.info("保存文档到Solr: CoreName=[{}], Class=[{}], ObjectJson={}", coreName, o.getClass(), JSON.toJSONString(o));
        }
        UpdateResponse updateResponse = solrClient.add(coreName, solrDocument);
        // 检查状态码
        int statusCode = updateResponse.getStatus();
        if (statusCode == 0) {
            solrClient.commit(coreName);
        }
        return statusCode == 0;
    }

    /**
     * 方法说明：查询solr中的分页数据
     *
     * @param queryStr  查询串
     * @param pageFrm   分页参数对象
     * @param clazz     查询的最终结果类字节码
     * @return 返回分页对象，一定不为null
     * @author ZhuYin
     * @since 2025年01月05日
     */
    public static PageVO<?> searchPage(String queryStr, PageFrm pageFrm, Class<?> clazz) throws Exception {
        return searchPage(null, queryStr, pageFrm, clazz);
    }

    /**
     * 方法说明：查询solr中的分页数据
     *
     * @param coreName  查询的core名称
     * @param queryStr  查询串
     * @param pageFrm   分页参数对象
     * @param clazz     查询的最终结果类字节码
     * @return 返回分页对象，一定不为null
     * @author ZhuYin
     * @since 2025年01月05日
     */
    public static PageVO<?> searchPage(String coreName, String queryStr, PageFrm pageFrm, Class<?> clazz) throws Exception {
        if (StringUtils.isBlank(queryStr)) {
            return PageVO.of(pageFrm.getPage(), pageFrm.getPageSize(), 0, Collections.emptyList());
        }
        SolrQuery solrQuery = new SolrQuery(queryStr);
        solrQuery.setStart((pageFrm.getPage() - 1) * pageFrm.getPageSize());
        solrQuery.setRows(pageFrm.getPageSize());
        if (StringUtils.isNotBlank(pageFrm.getSidx())) {
            solrQuery.addSort(pageFrm.getSidx(), pageFrm.getOrder().equalsIgnoreCase("desc") ? SolrQuery.ORDER.desc : SolrQuery.ORDER.asc);
        }
        if (SolrConfig.logEnabled) {
            log.info("Solr分页查询语句：{} start={} rows={}", queryStr, solrQuery.getStart(), solrQuery.getRows());
        }
        if (StringUtils.isBlank(coreName)) {
            SolrDocument annotation = clazz.getAnnotation(SolrDocument.class);
            coreName = annotation.collection();
            if (StringUtils.isBlank(coreName)) {
                log.error("实体类[{}]未标注@SolrDocument(collection = \"xxx\")注解，请补充", clazz);
                throw new MyException("实体类[" + clazz + "]未标注@SolrDocument(collection = \"xxx\")注解，请补充");
            }
        }
        QueryResponse response = solrClient.query(coreName, solrQuery);
        SolrDocumentList results = response.getResults();
        List<?> retList = SolrUtil.convertSolrDocumentList(results, clazz);
        return PageVO.of(pageFrm.getPage(), pageFrm.getPageSize(), (int) results.getNumFound(), retList);
    }

    /**
     * 方法说明：查询solr中集合数据
     *
     * @param queryStr 查询串
     * @param clazz    查询的最终结果类字节码
     * @return 返回查询结果集合，一定不为null
     * @author ZhuYin
     * @since 2025年01月05日
     */
    public static List<?> searchList(String queryStr, Class<?> clazz) throws Exception {
        return searchList(null, queryStr, clazz);
    }

    /**
     * 方法说明：查询solr中集合数据
     *
     * @param coreName 查询的core名称
     * @param queryStr 查询串
     * @param clazz    查询的最终结果类字节码
     * @return 返回查询结果集合，一定不为null
     * @author ZhuYin
     * @since 2025年01月05日
     */
    public static List<?> searchList(String coreName, String queryStr, Class<?> clazz) throws Exception {
        SolrQuery solrQuery = new SolrQuery(queryStr);
        if (SolrConfig.logEnabled) {
            log.info("Solr集合查询语句：{}", queryStr);
        }
        if (StringUtils.isBlank(coreName)) {
            SolrDocument annotation = clazz.getAnnotation(SolrDocument.class);
            coreName = annotation.collection();
            if (StringUtils.isBlank(coreName)) {
                log.error("实体类[{}]未标注@SolrDocument(collection = \"xxx\")注解，请补充", clazz);
                throw new MyException("实体类[" + clazz + "]未标注@SolrDocument(collection = \"xxx\")注解，请补充");
            }
        }
        QueryResponse response = solrClient.query(coreName, solrQuery);
        SolrDocumentList results = response.getResults();
        return  SolrUtil.convertSolrDocumentList(results, clazz);
    }

    /**
     * 方法说明：将查询到的SolrDocumentList转换为指定类型的对象集合
     *
     * @param results 查询到的SolrDocumentList
     * @param clazz   指定类的字节码
     * @return 返回指定类型的对象集合
     * @author ZhuYin
     * @since 2025年01月05日
     */
    private static List<?> convertSolrDocumentList(SolrDocumentList results, Class<?> clazz) {
        if (CollectionUtils.isEmpty(results)) {
            return Collections.emptyList();
        }
        List<Object> retList = new ArrayList<>();
        for (org.apache.solr.common.SolrDocument solrDocument : results) {
            try {
                Object o = clazz.newInstance();
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field field : declaredFields) {
                    if ("id".equalsIgnoreCase(field.getName())) {
                        ReflectionUtil.setFieldValue(o, field.getName(), solrDocument.getFieldValue(field.getName()));
                    }
                    SolrIndex annotation = field.getAnnotation(SolrIndex.class);
                    if (annotation != null) {
                        String solrFieldName = annotation.name();
                        Object fieldValue = solrDocument.getFieldValue(solrFieldName);
                        Object o1 = solrDocument.get(solrFieldName);
                        if (fieldValue != null) {
                            ReflectionUtil.setFieldValue(o, field.getName(), fieldValue);
                        }
                    }
                }
                retList.add(o);
            } catch (Exception e) {
                log.error("实例化对象失败：", e);
            }
        }
        return retList;
    }


}
